import $ from "jquery";
/**
 * 提示
 */
let tipDelayTiming, tipUpdateTiming;
$("body").on("mouseenter mousemove mouseleave", "[c-tip]", function (e) {
  e.stopPropagation();
  clearTimeout(tipDelayTiming);
  if (e.type === "mouseenter" || e.type === "mouseleave") {
    clearInterval(tipUpdateTiming);
    $(".c-tip").remove();
  }
  if (
    e.type === "mouseenter" ||
    (e.type === "mousemove" && !$(".c-tip").length)
  ) {
    tipDelayTiming = setTimeout(() => {
      tipShow(e, $(this));
    }, 500);
  }
});
/**
 * 显示提示信息
 *
 * @param {Event} e - 触发事件
 * @param {jQuery} $dom - 触发事件的DOM元素
 * @returns {boolean} - 如果不显示提示信息，返回false；否则返回true
 */
function tipShow(e, $dom) {
  // 获取DOM元素的自定义属性c-tip的值，作为提示文本
  let text = $dom.attr("c-tip");

  // 获取DOM元素的宽度
  const offsetWidth = $dom[0].offsetWidth;
  // 获取DOM元素的内容宽度
  const scrollWidth = $dom[0].scrollWidth;

  // 获取DOM元素的自定义属性c-tip-auto的值
  const auto = $dom.attr("c-tip-auto");

  // 如果没有文本或者c-tip-auto被设置且内容宽度小于等于元素宽度，则不显示提示信息
  if (!text || (auto !== undefined && scrollWidth <= offsetWidth)) {
    return false;
  }

  // 设置提示信息的默认类名
  let tipClass = "c-tip";

  // 获取DOM元素的自定义属性c-tip-class的值
  const customClass = $dom.attr("c-tip-class");

  // 如果有自定义类名，则将其添加到默认类名中
  if (customClass) {
    tipClass += " " + customClass;
  }

  // 构造提示信息的HTML字符串
  const str = `<i class="${tipClass}">${text}</i>`;

  // 将提示信息追加到body元素中
  $("body").append(str);

  // 调用tipFit函数处理提示信息的位置
  tipFit(e, $dom);

  // 调用tipUpdate函数更新提示信息
  tipUpdate(e, $dom);
}

/**
 * 更新提示信息并调整其位置
 *
 * @param {Event} e - 触发事件
 * @param {jQuery} $dom - 触发事件的DOM元素
 */
function tipUpdate(e, $dom) {
  // 设置一个定时器，每隔500毫秒执行一次更新操作
  tipUpdateTiming = setInterval(() => {
    // 更新提示信息的文本内容为DOM元素的c-tip属性值
    let text = $dom.attr("c-tip");
    $(".c-tip").html(text);
    if (!text) {
      $(".c-tip").remove();
    }
    // 调用tipFit函数调整提示信息的位置
    tipFit(e, $dom);
    // 如果DOM元素不可见，则清除定时器并移除提示信息
    if (!$dom.is(":visible")) {
      clearInterval(tipUpdateTiming);
      $(".c-tip").remove();
    }
  }, 500);
}

let x, y;
/**
 * 调整提示信息的位置
 *
 * @param {Event} e - 触发事件
 * @param {jQuery} $dom - 触发事件的DOM元素
 */
function tipFit(e, $dom) {
  // 获取提示信息的jQuery对象
  const $tip = $(".c-tip");
  // 获取窗口的宽度和高度
  const winW = $(window).width();
  const winH = $(window).height();
  // 获取提示信息的宽度和高度
  const tipW = $tip.outerWidth();
  const tipH = $tip.outerHeight();
  // 计算提示信息应该显示的位置
  x = e.clientX + 10;
  y = e.clientY + 14;

  // 如果提示信息在水平方向上超出了窗口宽度，则调整其位置
  if (x + tipW > winW) {
    x -= tipW + 18;
  }

  // 如果提示信息在垂直方向上超出了窗口高度，则调整其位置
  if (y + tipH > winH) {
    y -= tipH + 10;
  }

  // 设置提示信息的显示样式和位置
  $tip.css({
    display: "block",
    left: x,
    top: y,
  });

  // 获取DOM元素的自定义属性c-tip-placement的值，决定提示信息的显示位置
  const tipPlacement = $dom.attr("c-tip-placement");
  const domRect = $dom[0].getBoundingClientRect();

  // 根据提示信息的显示位置调用不同的函数进行位置调整
  if (tipPlacement === "top") {
    tipToTop(domRect, winW, winH, tipH, tipW);
  }
  if (tipPlacement === "bottom") {
    tipToBottom(domRect, winW, winH, tipH, tipW);
  }
  if (tipPlacement === "left") {
    tipToLeft(domRect, winW, winH, tipH, tipW);
  }
  if (tipPlacement === "right") {
    tipToRight(domRect, winW, winH, tipH, tipW);
  }

  // 再次设置提示信息的显示样式和位置，确保调整后的位置生效
  $tip.css({
    display: "block",
    left: x,
    top: y,
  });
}
/**
 * 将提示信息调整到触发元素的上方显示
 *
 * @param {DOMRect} domRect - 触发元素的边界矩形
 * @param {number} winW - 窗口的宽度
 * @param {number} winH - 窗口的高度
 * @param {number} tipH - 提示信息的高度
 * @param {number} tipW - 提示信息的宽度
 */
function tipToTop(domRect, winW, winH, tipH, tipW) {
  // 计算提示信息在水平方向上的位置，使其居中于触发元素
  x = domRect.left + domRect.width / 2 - tipW / 2;
  // 计算提示信息在垂直方向上的位置，使其位于触发元素的上方
  y = domRect.top - tipH - 4;
  // 如果提示信息在水平方向上超出了窗口的左侧边界，则调整其位置到窗口的左侧边界
  if (x < 0) {
    x = 0;
  }

  // 如果提示信息在水平方向上超出了窗口的右侧边界，则调整其位置到窗口的右侧边界
  if (x + tipW > winW) {
    x = winW - tipW;
  }

  // 如果提示信息在垂直方向上超出了窗口的顶部边界，则调整其位置到触发元素的下方
  if (y < 0) {
    y = domRect.bottom + 4;
  }
}
/**
 * 将提示信息调整到触发元素的下方显示
 *
 * @param {DOMRect} domRect - 触发元素的边界矩形
 * @param {number} winW - 窗口的宽度
 * @param {number} winH - 窗口的高度
 * @param {number} tipH - 提示信息的高度
 * @param {number} tipW - 提示信息的宽度
 */
function tipToBottom(domRect, winW, winH, tipH, tipW) {
  // 计算提示信息在水平方向上的位置，使其居中于触发元素
  x = domRect.left + domRect.width / 2 - tipW / 2;
  // 计算提示信息在垂直方向上的位置，使其位于触发元素的下方
  y = domRect.bottom + 4;
  // 如果提示信息在水平方向上超出了窗口的左侧边界，则调整其位置到窗口的左侧边界
  if (x < 0) {
    x = 0;
  }

  // 如果提示信息在水平方向上超出了窗口的右侧边界，则调整其位置到窗口的右侧边界
  if (x + tipW > winW) {
    x = winW - tipW;
  }

  // 如果提示信息在垂直方向上超出了窗口的底部边界，则调整其位置到触发元素的上方
  if (y + tipH > winH) {
    y = domRect.top - tipH - 4;
  }
}
/**
 * 将提示信息调整到触发元素的左侧显示
 *
 * @param {DOMRect} domRect - 触发元素的边界矩形
 * @param {number} winW - 窗口的宽度
 * @param {number} winH - 窗口的高度
 * @param {number} tipH - 提示信息的高度
 * @param {number} tipW - 提示信息的宽度
 */
function tipToLeft(domRect, winW, winH, tipH, tipW) {
  // 计算提示信息在水平方向上的位置，使其位于触发元素的左侧
  x = domRect.left - tipW - 4;
  // 计算提示信息在垂直方向上的位置，使其居中于触发元素
  y = domRect.top + domRect.height / 2 - tipH / 2;
  // 如果提示信息在水平方向上超出了窗口的左侧边界，则调整其位置到触发元素的右侧
  if (x < 0) {
    x = domRect.right + 4;
  }
}
/**
 * 将提示信息调整到触发元素的右侧显示
 *
 * @param {DOMRect} domRect - 触发元素的边界矩形
 * @param {number} winW - 窗口的宽度
 * @param {number} winH - 窗口的高度
 * @param {number} tipH - 提示信息的高度
 * @param {number} tipW - 提示信息的宽度
 */
function tipToRight(domRect, winW, winH, tipH, tipW) {
  // 计算提示信息在水平方向上的位置，使其位于触发元素的右侧
  x = domRect.right + 4;
  // 计算提示信息在垂直方向上的位置，使其居中于触发元素
  y = domRect.top + domRect.height / 2 - tipH / 2;
  // 如果提示信息在水平方向上超出了窗口的右侧边界，则调整其位置到触发元素的左侧
  if (x + tipW > winW) {
    x = domRect.left - tipW - 4;
  }
}
